package com.kly.user.task;

import cn.hutool.core.net.NetUtil;
import com.alibaba.fastjson.JSONObject;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.DateUtil;
import com.fqgj.exception.common.ApplicationException;
import com.fqgj.log.factory.LogFactory;
import com.fqgj.log.interfaces.Log;
import com.google.common.collect.Maps;
import com.kly.user.db.dao.UserTaskHistoryDao;
import com.kly.user.db.dao.UserTaskJobDao;
import com.kly.user.db.entity.UserTaskHistoryEntity;
import com.kly.user.db.entity.UserTaskJobEntity;
import com.kly.user.task.enums.TaskStatusEnum;
import com.kly.user.task.enums.TaskTypeEnum;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author linqu
 */
@Service
public class UserTaskExecutor {

    private static Log logger = LogFactory.getLog(UserTaskExecutor.class);

    @Resource
    UserTaskJobDao userTaskJobDao;
    @Resource
    Map<String, ExecuteHandler> handlers;
    Map<String, ExecuteHandler> executors = Maps.newHashMap();
    @Resource
    UserTaskHistoryDao userTaskHistoryDao;


    @PostConstruct
    public void buildHandle() {
        if (CollectionUtils.isEmpty(handlers)) {
            logger.error("UserTaskExecutor initialization failed");
            return;
        }
        handlers.forEach((k, handler) -> {
            final TaskTypeEnum taskType = handler.getType();
            executors.put(taskType.getName(), handler);
        });
    }

    public void executeJob(TaskTypeEnum taskType) {

        final List<UserTaskJobEntity> userTaskJobEntityList = userTaskJobDao.queryUserTask(taskType, taskType.getMaxExecuteTimes());
        if (CollectionUtils.isEmpty(userTaskJobEntityList)) {
            return;
        }
        for (UserTaskJobEntity entity : userTaskJobEntityList) {

            try {
                // 调用各类JOB处理器进行处理
                final ExecuteResult result = executors.get(TaskTypeEnum.getEnumByCode(entity.getTaskType()).getName()).doExecute(entity);
                // JOB执行结果
                if (Objects.nonNull(result) && TaskStatusEnum.SUCCESS.getCode().equals(result.getResultCode())) {
                    logger.info("ExecuteUserTaskJobSuccess, taskDetail={}", JSONObject.toJSONString(entity));
                    updeteExecStatusForRecord(taskType, entity, result);
                    return;
                }


                logger.error("ExecuteUserTaskJobFailed, taskDetail={}", JSONObject.toJSONString(entity));
                updeteExecStatusForRecord(taskType, entity, result);
                return;
            } catch (Exception e) {
                logger.error("ExecuteUserTaskJobFailed, taskDetail={}", JSONObject.toJSONString(entity), e);
                final ExecuteResult result = ExecuteResult.builder().taskType(taskType.getCode()).resultCode(TaskStatusEnum.FAILED.getCode())
                        .resultMsg(e.getMessage()).jobId(entity.getId()).build();
                updeteExecStatusForRecord(taskType, entity, result);
            }

        }
    }

    private void updeteExecStatusForRecord(TaskTypeEnum taskType, UserTaskJobEntity entity, ExecuteResult result) {

        // maxExecuteTimes未指定值为长期任务，长期任务不更新状态，只记录日志
        if (Objects.nonNull(taskType.getMaxExecuteTimes())) {
            entity.setStatus(result.getResultCode());
        }
        entity.setExecuteTimes(entity.getExecuteTimes() == null ? 0 : entity.getExecuteTimes() + 1);
        entity.setNextJobTime(getDateLater(taskType.getReTryTimeLength()));
        userTaskJobDao.updateByPrimaryKey(entity);

        // 历史记录
        doLog(result);

    }


    public static Date getDateLater(int second) {
        Calendar now = Calendar.getInstance();
        now.add(Calendar.SECOND, second);
        String nowDate = DateUtil.getDate(now.getTime(), "yyyy-MM-dd HH:mm:ss");
        Date date = null;
        try {
            date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(nowDate);
        } catch (ParseException pe) {
        }
        return date;
    }

    public void doLog(ExecuteResult result) {
        if (Objects.isNull(result)) {
            return;
        }
        UserTaskHistoryEntity entity = new UserTaskHistoryEntity();
        entity.setBusiId(result.getBusiId());
        entity.setJobId(result.getJobId());
        entity.setParams(result.getParams());
        entity.setResult(result.getResultMsg());
        entity.setTaskType(result.getTaskType());
        entity.setStatus(result.getResultCode());
        userTaskHistoryDao.insert(entity);
    }
}
